<?php

declare(strict_types=1);

namespace App\Service;

use App\Models\PaymentOrder;
use Carbon\Carbon;
use Hyperf\Di\Annotation\Inject;
use Hyperf\HttpMessage\Exception\HttpException;
use Hyperf\Logger\LoggerFactory;
use Hyperf\Utils\Codec\Json;
use Psr\Log\LoggerInterface;

class PaymentService
{
    /**
     * @Inject()
     * @var WechatFactory
     */
    protected $wechatFactory;

    /**
     * @var LoggerInterface
     */
    protected $logger;

    public function __construct(LoggerFactory $loggerFactory)
    {
        $this->logger = $loggerFactory->get('log', 'default');
    }

    public function defray($data)
    {
        // 生成收银台订单
        $paymentOrder = PaymentOrder::query()->create([
            'order_id' => $this->generateOrderId($data['channel']),
            'amount' => $data['amount'],
            'payment_channel' => $data['channel'],
            'subject' => $data['subject'] ?? '',
            'body' => $data['body'] ?? '',
            'remark' => $data['remark'] ?? '',
        ]);

        // 下渠道订单
        $channelMethod = 'defrayChannel' . PaymentOrder::PAYMENT_CHANNEL_ABBREVIATION_MAP[$data['channel']];

        return [
            $paymentOrder,
            $this->{$channelMethod}($data, $paymentOrder)
        ];
    }

    /**
     * 生成收银台订单 ID
     * @param $channel
     * @return string
     * @throws \Exception
     */
    private function generateOrderId($channel)
    {
        return PaymentOrder::PAYMENT_CHANNEL_ABBREVIATION_MAP[$channel] . Carbon::now()->format('YmdHisu') . random_int(0, 9);
    }

    /**
     * 微信预订单
     * @param $data
     * @param PaymentOrder $paymentOrder
     * @return array|\EasyWeChat\Kernel\Support\Collection|object|\Psr\Http\Message\ResponseInterface|string
     * @throws \EasyWeChat\Kernel\Exceptions\InvalidArgumentException
     * @throws \EasyWeChat\Kernel\Exceptions\InvalidConfigException
     * @throws \GuzzleHttp\Exception\GuzzleException
     */
    private function defrayChannelWX($data, PaymentOrder $paymentOrder)
    {
        $wxOrder = [
            'body' => $paymentOrder['body'],
            'out_trade_no' => $data['out_trade_no'], // 业务订单号
            'total_fee' => $paymentOrder['amount'],
            'trade_type' => $data['trade_type'],
        ];
        $data['trade_type'] === 'JSAPI' && $wxOrder['openid'] = $data['openid'];
        !empty($data['notify_url']) && $wxOrder['notify_url'] = $data['notify_url'];

        $channelOrder = $this->wechatFactory->payment()->order->unify($wxOrder); // 微信下预订单
        $this->logger->info('微信下单返回: ' . Json::encode($channelOrder));
        if ($channelOrder['return_code'] === 'FAIL') {
            throw new HttpException(400, '微信下单失败 (' . ($channelOrder['return_msg'] ?? '') . ')');
        }
        if ($channelOrder['result_code'] === 'FAIL') {
            throw new HttpException(400, '微信下单失败 (' . ($channelOrder['err_code_des'] ?? '') . ')');
        }

        $paymentOrder->channelWechat()->create([
            'order_id' => $paymentOrder['order_id'],
            'trade_type' => $data['trade_type'],
            'out_trade_no' => $data['out_trade_no'],
            'total_fee' => $paymentOrder['amount'],
            'started_at' => Carbon::now(),
            'prepay_id' => $channelOrder['prepay_id'],
        ]);

        return $channelOrder;
    }
}
